package com.qfedu.psys.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.Resource;
import javax.transaction.Transactional;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.qfedu.common.util.WoUtil;
import com.qfedu.psys.PSysException;
import com.qfedu.psys.dto.MenuDto;
import com.qfedu.psys.dto.WoUser;
import com.qfedu.psys.po.Menu;
import com.qfedu.psys.po.Role;
import com.qfedu.psys.po.User;
import com.qfedu.psys.repository.MenuRepository;
import com.qfedu.psys.repository.UserRepository;
import com.qfedu.psys.service.CoreService;
import com.qfedu.psys.service.UserExtensionService;
import com.qfedu.psys.util.PSysConstant;

/**
 * 
 * @author cailei
 * @date Nov 7, 2018
 */
@Service
@Transactional
public class CoreServiceImpl implements CoreService {

	private final static Logger LOG = LogManager.getLogger(CoreServiceImpl.class);
	
	/**
	 * 注入UserRepository.
	 */
	@Resource // @Autowired
	private UserRepository userRepository;
	
	/**
	 * 注入MenuRepository.
	 */
	@Resource // @Autowired
	private MenuRepository menuRepository;
	
	@Value("${sys.user.extension}")
	private String userExtensionName;
	
	@Override
	public WoUser authenticate(String user, String password, String roleId) {
		User u = userRepository.findByLoginName(user);
		LOG.info("user:" + user + ", role:" + roleId);
		if (u == null) {
			throw new PSysException(PSysConstant.ERR_LOGIN);
		}
		// u.setRoles(roleDao.findAllByUserId(u.getId()));
		LOG.info("authenticate-roles:" + u.getRoles().size());
		if (password != null) {
			// 验证密码
			String md5 = WoUtil.getMD5(u.getId(), password);
			if (!md5.equals(u.getPassword())) {
				throw new PSysException(PSysConstant.ERR_LOGIN);
			}
		}
		
		Boolean roleIn = false;
		for (Role r : u.getRoles()) {
			if (r.getId().equals(roleId)) {
				roleIn = true;
			}
		}
		if (!roleIn) {
			throw new PSysException(PSysConstant.ERR_LOGIN_ROLE);
		}
		// 构造dto，从用户角色关系表中获取角色信息
		WoUser dto = new WoUser(u);
		dto.setCurrentRoleId(roleId);
		// 开放接口，让后续项目，可以设置自定义用户角色信息
		WoUtil.getBean(userExtensionName, UserExtensionService.class).setUserInfo(dto);
		LOG.info("用户【" + dto.getLoginName() + "】验证通过...");
		return dto;
	}

	private MenuDto setCurrent(List<MenuDto> dtos, String menuId) {
		for (MenuDto dto : dtos) {
			if (dto.getId().equals(menuId)) {
				dto.setCurrent(true);
				return dto;
			}
		}
		return null;
	}

	private void setFirstCurrent(List<MenuDto> dtos) {
		if (dtos.size() > 0) {
			dtos.get(0).setCurrent(true);
		}
	}

	private void setFirstAndChildCurrent(List<MenuDto> dtos) {
		if (dtos.size() > 0) {
			MenuDto m = dtos.get(0);
			m.setCurrent(true);
			this.setFirstCurrent(m.getChildren());
		}
	}

	@Override
	public List<MenuDto> getMenus(WoUser u, String topId, String subId) {
		List<Menu> menus = new ArrayList<Menu>();
		// 返回当前用户具有权限的顶级菜单dto
		List<MenuDto> menuDtos = new ArrayList<MenuDto>();
		if (u.isAdmin()) {
			menus = menuRepository.findAllByParentIdIsNullOrderByNo();
			/*
			 * for (Menu m : menus) {
			 * m.setChildren(menuRepository.findAllByParentIdOrderByNo(m.getId()
			 * )); }
			 */
			menuDtos = MenuDto.getDtos(menus);
		} else {
			// 获取当前用户角色有权限的顶级或者子菜单
			menus = menuRepository.findAllByRoleIds(Arrays.asList(WoUtil.splitIds(u.getCurrentRoleId())));
			/*
			 * for (Menu m : menuRepository.findAll()) { if
			 * (SecurityUtils.getSubject().isPermitted(m.getId())) {
			 * menus.add(m); } }
			 */
			// 对菜单根据no排序，顶级菜单在前，紧跟其后的是其子菜单
			MenuDto.sort(menus);
			// 将包含子菜单的列表，转化为仅有顶级菜单的列表
			for (Menu m : menus) {
				if (m.getParent() == null) {
					MenuDto dto = new MenuDto(m);
					dto.getChildren().clear();
					menuDtos.add(dto);
				} else {
					menuDtos.get(menuDtos.size() - 1).getChildren().add(new MenuDto(m));
				}
				// }
			}
		}
		if (!WoUtil.isEmpty(topId)) {
			MenuDto top = this.setCurrent(menuDtos, topId);
			if (WoUtil.isEmpty(subId)) {
				this.setFirstCurrent(top.getChildren());
			} else {
				this.setCurrent(top.getChildren(), subId);
			}
		} else {
			this.setFirstAndChildCurrent(menuDtos);
		}
		return menuDtos;
	}

}
